#pragma once
#include "InetAddr.hpp"
#include "Common.hpp"
#include <sys/types.h>
#include "Socket.hpp"
#include <sys/wait.h>
#include <memory>
#include <signal.h>
#include <poll.h>

// #include "Cal.hpp"
// #include "Protocol.hpp"

namespace kzz
{
    class PollServer
    {
    public:
        const static int size = sizeof(fd_set) * 8;
        const static int defaultfd = -1;

        PollServer(int port)
            : _listensockfd(std::make_unique<TcpSocket>()), _port(port)
        {
            _listensockfd->BuildTcpServerSocketMethod(_port);
            for (int i = 0; i < size; i++)
            {
                //_fd_array[i] = defaultfd;
                _fds[i].fd=defaultfd;
                _fds[i].events=POLLIN;
                _fds[i].revents=0;
            }
            //_fd_array[0] = _listensockfd->Fd();
            _fds[0].fd= _listensockfd->Fd();;
        }
        void Start()
        {

            _isrunning = true;

            while (_isrunning)
            {
                    int timeout=-1;
                int n=poll(_fds,size,timeout);

                
                switch (n)
                {
                case -1: // 出错
                    LOG(LogLevel::ERROR) << "select errror";
                    break;
                case 0: // 超时
                    LOG(LogLevel::ERROR) << "timeout";
                    break;
                default: // 有可以处理的事务了
                    LOG(LogLevel::DBUGER) << "有事务就绪了......";
                    Dispatcher(); // 处理就绪事务
                    break;
                }
            }
        }
        void Accepter()
        {
            InetAddr clientaddr;
            int fd = _listensockfd->Accept(clientaddr)->Fd();
            // 将新获取到的文件描述符放入_fds
            if (fd > 0)
            {
                int pos = 0;
                for (; pos < size; pos++)
                {
                    if (_fds[pos].fd == defaultfd)
                    {
                        break;
                    }
                }
                if (pos == size)
                {
                    LOG(LogLevel::DBUGER) << "select full";
                    return;
                }
                _fds[pos].fd = fd;
                _fds[pos].events=POLLIN;
                _fds[pos].revents=0;
            }
        }
        // 传入fd和pos,如果对端关闭，把pos从辅助数组中拿出来
        void Recv(int pos)
        {
            char buffer[1024];
            int n = recv(_fds[pos].fd, buffer, sizeof(buffer), 0);
            if (n < 0)
            {
                // 出错
                //必须先关闭，后关闭的话关的就是-1了
                LOG(LogLevel::DBUGER) << _fds[pos].fd << "出错";
                //1.
                close(_fds[pos].fd);
                //2. 
                _fds[pos].fd = defaultfd;
                _fds[pos].events=0;
                _fds[pos].revents=0;

            }
            else if (n == 0)
            {
                // 对端关闭
                LOG(LogLevel::DBUGER) <<_fds[pos].fd<< "对端关闭";
                 close(_fds[pos].fd);
                _fds[pos].fd = defaultfd;
                _fds[pos].events=0;
                _fds[pos].revents=0;
            }
            else
            {
                buffer[n] = 0;
                std::cout << "client echo:" << buffer << std::endl;
            }
        }
        void Dispatcher()
        {
            // 检查辅助数组中的谁就绪了
            for (int i = 0; i < size; i++)
            {
                if (_fds[i].fd == defaultfd)
                    continue;

                // 判断这个文件是否读就绪
                if (_fds[i].revents & POLLIN)
                {
                    // 再判断是listen还是其他
                    if (_fds[i].fd == _listensockfd->Fd())
                    {
                        // listen来新连接了
                        Accepter();
                    }
                    else
                    {
                        // 普通事件
                        Recv(i);
                    }
                }
                else
                {
                    //写就绪
                }
            }
        }

    private:
        std::unique_ptr<Socket> _listensockfd;
        uint16_t _port;
        bool _isrunning;
        int _fd_array[size];
        struct pollfd _fds[size];
    };

}